package com.mall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.mall.common.dto.SpuInfoDTO;
import com.mall.common.page.PageData;
import com.mall.common.service.impl.CrudServiceImpl;
import com.mall.common.utils.ConvertUtils;
import com.mall.common.utils.Result;
import com.mall.product.dao.SkuInfoDao;
import com.mall.product.dto.SeckillSkuRedisDTO;
import com.mall.product.dto.SkuImagesDTO;
import com.mall.product.dto.SkuInfoDTO;
import com.mall.product.dto.SpuInfoDescDTO;
import com.mall.product.entity.*;
import com.mall.product.feign.SeckillFeignClient;
import com.mall.product.service.*;
import com.mall.product.vo.SkuItemSaleAttrVo;
import com.mall.product.vo.SkuItemVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * sku信息
 *
 * @author xjc xjc@163.com
 * @since 1.0.0 2022-07-17
 */
@Service
@Slf4j
public class SkuInfoServiceImpl extends CrudServiceImpl<SkuInfoDao, SkuInfoEntity, SkuInfoDTO> implements SkuInfoService {

    @Resource
    private SkuImagesService skuImagesService;
    @Resource
    private SpuInfoDescService spuInfoDescService;
    @Resource
    private AttrGroupService attrGroupService;
    @Resource
    private SkuSaleAttrValueService skuSaleAttrValueService;
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;
    @Resource
    private SpuInfoService spuInfoService;
    @Resource
    private SeckillFeignClient seckillFeignClient;

    @Override
    public QueryWrapper<SkuInfoEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");

        QueryWrapper<SkuInfoEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(id), "id", id);

        return wrapper;
    }

    @Override
    public PageData<SkuInfoDTO> queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SkuInfoEntity> queryWrapper = new QueryWrapper<>();
        String key = (String) params.get("key");
        if (key != null && !StringUtils.isEmpty(key))
            queryWrapper.and(q -> {
                q.eq("id", key).or().like("spu_name", key);
            });
        BigDecimal min = strParseBigDecimal(params.get("min"));
        BigDecimal max = strParseBigDecimal(params.get("max"));
        if (max.compareTo(min) > 0&&max.compareTo(new BigDecimal("0"))>0){
            queryWrapper.ge("price", min);
            queryWrapper.le("price", max);
        }
        BigDecimal brandId = strParseBigDecimal(params.get("brandId"));
        if (brandId.compareTo(new BigDecimal("0"))>0)
            queryWrapper.eq("brand_id", brandId);
        BigDecimal catelogId = strParseBigDecimal(params.get("catelogId"));
        if (catelogId.compareTo(new BigDecimal("0"))>0)
            queryWrapper.eq("catelog_id", catelogId);
        IPage<SkuInfoEntity> selectPage = baseDao.selectPage(getPage(params, null, false), queryWrapper);
        List<SkuInfoDTO> dtoList = ConvertUtils.sourceToTarget(selectPage.getRecords(), SkuInfoDTO.class);
        PageData<SkuInfoDTO> pageData = new PageData<>(dtoList, selectPage.getTotal());
        return pageData;
    }

    @Override
    public List<SkuInfoEntity> selectBySpuId(Long spuId) {
        QueryWrapper<SkuInfoEntity> wrapper = new QueryWrapper<SkuInfoEntity>().eq("spu_id", spuId);
        List<SkuInfoEntity> selectList = baseDao.selectList(wrapper);
        return selectList;
    }

    @Override
    public SkuItemVo item(Long skuId) {
        SkuItemVo skuItemVo = new SkuItemVo();
        // sku_info
        CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
            SkuInfoEntity skuInfoEntity = baseDao.selectById(skuId);
            skuItemVo.setSkuInfo(ConvertUtils.sourceToTarget(skuInfoEntity, SkuInfoDTO.class));
            return skuInfoEntity;
        }, threadPoolExecutor);
        // sku_spu
        CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync(info -> {
            List<SkuItemSaleAttrVo> saleAttrs = skuSaleAttrValueService.getSaleAttrsBySpuId(info.getSpuId());
            skuItemVo.setSaleAttr(saleAttrs);
        }, threadPoolExecutor);
        // spu_desc
        CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync(info -> {
            SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.selectById(info.getSpuId());
            skuItemVo.setSpuInfoDesc(ConvertUtils.sourceToTarget(spuInfoDescEntity, SpuInfoDescDTO.class));
        }, threadPoolExecutor);
        // spu_attr
        CompletableFuture<Void> spuAttrFuture = infoFuture.thenAcceptAsync(info -> {
            List<SkuItemVo.SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(info.getSpuId(), info.getCatelogId());
            skuItemVo.setGroupVos(attrGroupVos);
        }, threadPoolExecutor);

        // sku_img
        CompletableFuture<Void> imgFuture = CompletableFuture.runAsync(() -> {
            List<SkuImagesEntity> images = skuImagesService.listBySkuId(skuId);
            skuItemVo.setSkuImages(ConvertUtils.sourceToTarget(images, SkuImagesDTO.class));
        },threadPoolExecutor);
        // 获取秒杀
        CompletableFuture<Void> seckillFuture = CompletableFuture.runAsync(()->{
            Result<SeckillSkuRedisDTO> seckillInfo = seckillFeignClient.getSkuSeckillInfo(skuId);
            if (seckillInfo.getCode()==0){
                SeckillSkuRedisDTO data = seckillInfo.getData();
                skuItemVo.setSkuSeckillInfo(data);
            }
        },threadPoolExecutor);
        // 等待所有任务
        try {
            CompletableFuture.allOf(infoFuture,seckillFuture,spuAttrFuture,saleAttrFuture,imgFuture,descFuture).get();
        } catch (Exception e) {
           log.error("异步编排任务异常："+e.getMessage());
           throw new RuntimeException(e.getMessage());
        }
        return skuItemVo;
    }

    @Override
    public List<String> getAttrNameAndValue(Long skuId) {
        return baseDao.getAttrNameAndValue(skuId);
    }

    @Override
    public Map<String, BigDecimal> getPricesBySkuIds(List<Long> skuIds) {
        List<SkuInfoEntity> skuInfoEntities = baseDao.selectBatchIds(skuIds);
        return skuInfoEntities.stream().collect(Collectors.toMap(skuInfoEntity -> String.valueOf(skuInfoEntity.getSkuId()), SkuInfoEntity::getPrice));
    }

    @Override
    public SpuInfoDTO getSpuInfoBySkuId(Long skuId) {
        SkuInfoEntity skuInfoEntity = baseDao.selectById(skuId);
        SpuInfoEntity infoEntity = spuInfoService.selectById(skuInfoEntity.getSpuId());
        return ConvertUtils.sourceToTarget(infoEntity,SpuInfoDTO.class);
    }

    public BigDecimal strParseBigDecimal(Object str) {
        String temp = (String) str;
        if (str == null || StringUtils.isEmpty(temp))
            return new BigDecimal("0");
        else
            try {
                return new BigDecimal(temp);
            } catch (Exception e) {
                return new BigDecimal("0");
            }
    }
}